home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fsio / fsioStream.c < prev    next >
C/C++ Source or Header  |  1991-05-06  |  38KB  |  1,128 lines

  1. /* 
  2.  * fsioStream.c --
  3.  *
  4.  *    There are two sets of procedures here.  The first manage the stream
  5.  *    as it relates to the handle table; streams are installed in this
  6.  *    table so that handle synchronization primitives can be used, and
  7.  *    so that streams can be found after migration.  The golden rule is
  8.  *    that the stream's refCount reflects local use, and its client list
  9.  *    is used to reflect remote use of a stream.  Thus I/O server's
  10.  *    don't keep references, only client list entries, unless there is
  11.  *    a local user.
  12.  *
  13.  *    The second set of procedures handle the mapping from streams to
  14.  *    user-level stream IDs,    which are indexes into a per-process array
  15.  *    of stream pointers.
  16.  *
  17.  * Copyright (C) 1987 Regents of the University of California
  18.  * All rights reserved.
  19.  * Permission to use, copy, modify, and distribute this
  20.  * software and its documentation for any purpose and without
  21.  * fee is hereby granted, provided that the above copyright
  22.  * notice appear in all copies.  The University of California
  23.  * makes no representations about the suitability of this
  24.  * software for any purpose.  It is provided "as is" without
  25.  * express or implied warranty.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /sprite/src/kernel/fsio/RCS/fsioStream.c,v 9.16 91/05/06 14:29:27 kupfer Exp $ SPRITE (Berkeley)";
  30. #endif not lint
  31.  
  32.  
  33. #include <sprite.h>
  34. #include <fs.h>
  35. #include <fsutil.h>
  36. #include <fsio.h>
  37. #include <fsNameOps.h>
  38. #include <fsconsist.h>
  39. #include <fsStat.h>
  40. #include <fsrmt.h>
  41. #include <proc.h>
  42. #include <procMigrate.h>
  43. #include <sync.h>
  44. #include <rpc.h>
  45. #include <fsioRpc.h>
  46. #include <stdio.h>
  47.  
  48. /*
  49.  * Monitor to synchronize access to the streamCount variable.
  50.  */
  51. static    Sync_Lock    streamLock = Sync_LockInitStatic("Fs:streamLock");
  52. #define LOCKPTR (&streamLock)
  53.  
  54. static int    streamCount;    /* Used to generate fileIDs for streams*/
  55.  
  56. /*
  57.  * Forward declarations. 
  58.  */
  59. static ReturnStatus StreamMigCallback _ARGS_((Fsio_MigInfo *migInfoPtr, 
  60.             Boolean *sharedPtr, int *offsetPtr));
  61.  
  62.  
  63. /*
  64.  *----------------------------------------------------------------------
  65.  *
  66.  * Fsio_StreamCreate --
  67.  *
  68.  *    Create a new stream for a client.  This chooses a unique minor number
  69.  *    for the    fileID of the stream, installs it in the handle table,
  70.  *    and initializes the client list to contain the client.  This is
  71.  *    used on the file server to remember clients of regular files, and
  72.  *    when creating pipe streams which need client info for migration.
  73.  *
  74.  * Results:
  75.  *    A pointer to a locked stream with 1 reference and one client entry.
  76.  *
  77.  * Side effects:
  78.  *    Install the new stream into the handle table and increment the global
  79.  *    streamCount used to generate IDs.  The stream is returned locked and
  80.  *    with one reference.  Our caller should release this reference if
  81.  *    this is just a shadow stream.
  82.  *
  83.  *----------------------------------------------------------------------
  84.  */
  85. ENTRY Fs_Stream *
  86. Fsio_StreamCreate(serverID, clientID, ioHandlePtr, useFlags, name)
  87.     int            serverID;    /* I/O server for stream */
  88.     int            clientID;    /* Client of the stream */
  89.     Fs_HandleHeader    *ioHandlePtr;    /* I/O handle to attach to stream */
  90.     int            useFlags;    /* Usage flags from Fs_Open call */
  91.     char        *name;        /* Name for error messages */
  92. {
  93.     register Boolean found;
  94.     register Fs_Stream *streamPtr;
  95.     Fs_Stream *newStreamPtr;
  96.     Fs_FileID fileID;
  97.  
  98.     LOCK_MONITOR;
  99.  
  100.     /*
  101.      * The streamID is uniquified by using our own host ID for the major
  102.      * field (for network uniqueness), and then choosing minor
  103.      * numbers until we don't have a local conflict.
  104.      */
  105.     fileID.type = FSIO_STREAM;
  106.     fileID.serverID = serverID;
  107.     fileID.major = rpc_SpriteID;
  108.  
  109.     do {
  110.     fileID.minor = ++streamCount;
  111.     found = Fsutil_HandleInstall(&fileID, sizeof(Fs_Stream), name,
  112.                 FALSE, (Fs_HandleHeader **)&newStreamPtr);
  113.     if (found) {
  114.         /*
  115.          * Don't want to conflict with existing streams.
  116.          */
  117.         Fsutil_HandleRelease(newStreamPtr, TRUE);
  118.     }
  119.     } while (found);
  120.  
  121.     streamPtr = newStreamPtr;
  122.     streamPtr->offset = 0;
  123.     streamPtr->flags = useFlags;
  124.     streamPtr->ioHandlePtr = ioHandlePtr;
  125.     streamPtr->nameInfoPtr = (Fs_NameInfo *)NIL;
  126.     List_Init(&streamPtr->clientList);
  127.     fs_Stats.object.streams++;
  128.  
  129.     (void)Fsio_StreamClientOpen(&streamPtr->clientList, clientID, useFlags,
  130.         (Boolean *)NIL);
  131.  
  132.     UNLOCK_MONITOR;
  133.     return(streamPtr);
  134. }
  135.  
  136. /*
  137.  *----------------------------------------------------------------------
  138.  *
  139.  * Fsio_StreamAddClient --
  140.  *
  141.  *    Find a stream and add another client to its client list.
  142.  *
  143.  * Results:
  144.  *    A pointer to a locked stream with 1 reference and one or more 
  145.  *    client entries.  Our call should release this reference if 
  146.  *    this is just a shadow stream.
  147.  *
  148.  * Side effects:
  149.  *    Install the stream into the handle table if it's not there 
  150.  *    already.
  151.  *
  152.  *----------------------------------------------------------------------
  153.  */
  154. Fs_Stream *
  155. Fsio_StreamAddClient(streamIDPtr, clientID, ioHandlePtr, useFlags, name,
  156.         foundClientPtr, foundStreamPtr)
  157.     Fs_FileID        *streamIDPtr;    /* File ID for stream */
  158.     int            clientID;    /* Client of the stream */
  159.     Fs_HandleHeader    *ioHandlePtr;    /* I/O handle to attach to stream */
  160.     int            useFlags;    /* Usage flags from Fs_Open call */
  161.     char        *name;        /* Name for error messages */
  162.     /*
  163.      * These two boolean pointers may be NIL if their info is not needed.
  164.      */
  165.     Boolean        *foundClientPtr;/* True if Client already existed */
  166.     Boolean        *foundStreamPtr;/* True if stream already existed */
  167. {
  168.     register Boolean found;
  169.     register Fs_Stream *streamPtr;
  170.     Fs_Stream *newStreamPtr;
  171.  
  172.     found = Fsutil_HandleInstall(streamIDPtr, sizeof(Fs_Stream), name,
  173.                 FALSE, (Fs_HandleHeader **)&newStreamPtr);
  174.     streamPtr = newStreamPtr;
  175.     if (!found) {
  176.     streamPtr->offset = 0;
  177.     streamPtr->flags = useFlags;
  178.     streamPtr->ioHandlePtr = ioHandlePtr;
  179.     streamPtr->nameInfoPtr = (Fs_NameInfo *)NIL;
  180.     List_Init(&streamPtr->clientList);
  181.     fs_Stats.object.streams++;
  182.     } else if (streamPtr->ioHandlePtr == (Fs_HandleHeader *)NIL) {
  183.     streamPtr->ioHandlePtr = ioHandlePtr;
  184.     }
  185.     (void)Fsio_StreamClientOpen(&streamPtr->clientList, clientID, useFlags,
  186.         foundClientPtr);
  187.     if (foundStreamPtr != (Boolean *)NIL) {
  188.     *foundStreamPtr = found;
  189.     }
  190.  
  191.     return(streamPtr);
  192. }
  193.  
  194. /*
  195.  *----------------------------------------------------------------------
  196.  *
  197.  * Fsio_StreamMigClient --
  198.  *
  199.  *    This is called on the I/O server for to move client streams refs.
  200.  *    This makes a callback to the source client to release the reference
  201.  *    to the stream which has (now) moved away.
  202.  *    Note:  this operation locks the stream in order to serialize
  203.  *    with a close comming in from a remote client who has dup'ed the
  204.  *    stream, migrated one reference, and closed the other reference.
  205.  *    Also, on the client the callback and the regular close will both
  206.  *    try to lock the stream in order to release a reference.  Deadlock
  207.  *    cannot occur because if the close happens first there will be two
  208.  *    references at the client.  The close at the client will release
  209.  *    one reference and not try to contact us.  If the callback occurs
  210.  *    first then the close will come through to us, but it will have
  211.  *    to wait until we are done with this migration.
  212.  *
  213.  * Results:
  214.  *    TRUE if the stream is shared across the network after migration.
  215.  *
  216.  * Side effects:
  217.  *    Shifts the client list entry from one host to another.  This does
  218.  *    not add/subtract any references to the stream here on this host.
  219.  *    However, the call-back releases a reference at the source client.
  220.  *
  221.  *----------------------------------------------------------------------
  222.  */
  223. ENTRY void
  224. Fsio_StreamMigClient(migInfoPtr, dstClientID, ioHandlePtr, closeSrcClientPtr)
  225.     Fsio_MigInfo        *migInfoPtr;    /* Encapsulated stream */
  226.     int            dstClientID;    /* New client of the stream */
  227.     Fs_HandleHeader    *ioHandlePtr;    /* I/O handle to attach to stream */
  228.     Boolean        *closeSrcClientPtr;    /* Return - TRUE if the src
  229.                      * client stopped using stream */
  230. {
  231.     register Boolean found;
  232.     register Fs_Stream *streamPtr;
  233.     Fs_Stream *newStreamPtr;
  234.     int newClientStream = migInfoPtr->flags & FS_NEW_STREAM;
  235.     ReturnStatus status;
  236.     Boolean shared;
  237.     int offset;
  238.  
  239.     /*
  240.      * Get the stream and synchronize with closes from the client.
  241.      * The I/O handle has to be unlocked while the stream is locked
  242.      * in order to prevent deadlock with un-related open/close activity.
  243.      */
  244.     Fsutil_HandleUnlock(ioHandlePtr);
  245.     found = Fsutil_HandleInstall(&migInfoPtr->streamID, sizeof(Fs_Stream),
  246.              (char *)NIL, FALSE, (Fs_HandleHeader **)&newStreamPtr);
  247.     streamPtr = newStreamPtr;
  248.     if (!found) {
  249.     streamPtr->offset = migInfoPtr->offset;
  250.     streamPtr->flags = migInfoPtr->flags & ~FS_NEW_STREAM;
  251.     streamPtr->ioHandlePtr = ioHandlePtr;
  252.     streamPtr->nameInfoPtr = (Fs_NameInfo *)NIL;
  253.     List_Init(&streamPtr->clientList);
  254.     fs_Stats.object.streams++;
  255.     } else if (streamPtr->ioHandlePtr == (Fs_HandleHeader *)NIL) {
  256.     streamPtr->ioHandlePtr = ioHandlePtr;
  257.     }
  258.     if (migInfoPtr->srcClientID != rpc_SpriteID) {
  259.     /*
  260.      * Call back to the client to tell it to release its reference
  261.      * on the stream.  We can't hold the I/O handle locked because
  262.      * an unrelated close from the source client might have the
  263.      * I/O handle locked over there.  By unlocking this I/O handle
  264.      * we allow unrelated closes to complete, while the stream
  265.      * lock prevents closes of other references to this stream
  266.      * from coming in and changing the state.
  267.      */
  268.     status = StreamMigCallback(migInfoPtr, &shared, &offset);
  269.     if ((streamPtr->flags & FS_RMT_SHARED) == 0) {
  270.         /*
  271.          * We don't think the stream is being shared so we
  272.          * grab the offset from the client.
  273.          */
  274.         if (offset == -1) {
  275.         /*
  276.          * Temporary case for clients who can't return it.
  277.          */
  278.         streamPtr->offset = migInfoPtr->offset;
  279.         } else {
  280.         streamPtr->offset = offset;
  281.         }
  282.     }
  283.     } else {
  284.     /*
  285.      * The stream has been migrated away from us, the I/O server.
  286.      * Decrement the stream ref count.  The I/O handle references
  287.      * are left alone here on the I/O server.
  288.      */
  289.     Fsutil_HandleDecRefCount((Fs_HandleHeader *)streamPtr);
  290.     shared = (streamPtr->hdr.refCount > 1);
  291.     status = SUCCESS;
  292.     }
  293.  
  294.     if (status != SUCCESS || !shared) {
  295.     /*
  296.      * The client doesn't perceive sharing of the stream so
  297.      * it must be its last reference so we indicate an I/O close is needed.
  298.      */
  299.     *closeSrcClientPtr = TRUE;
  300.     (void)Fsio_StreamClientClose(&streamPtr->clientList,
  301.                   migInfoPtr->srcClientID);
  302.     } else {
  303.     *closeSrcClientPtr = FALSE;
  304.     }
  305.     /*
  306.      * Mark (unmark) the stream if it is being shared.  This is checked
  307.      * in the read and write RPC stubs in order to know what offset to use,
  308.      * the one here in the shadow stream, or the one from the client.
  309.      */
  310.     if (Fsio_StreamClientOpen(&streamPtr->clientList, dstClientID,
  311.                 migInfoPtr->flags, (Boolean *)NIL)) {
  312.     streamPtr->flags |= FS_RMT_SHARED;
  313.     } else {
  314.     streamPtr->flags &= ~FS_RMT_SHARED;
  315.     }
  316.     migInfoPtr->flags = streamPtr->flags | newClientStream;
  317.     migInfoPtr->offset = streamPtr->offset;
  318.     Fsutil_HandleRelease(streamPtr, TRUE);
  319.     Fsutil_HandleLock(ioHandlePtr);
  320. }
  321.  
  322. /*
  323.  * Parameters and results for RPC_FS_RELEASE that is called
  324.  * to release a reference to a stream on the source of a migration.
  325.  */
  326. typedef struct {
  327.     Fs_FileID streamID;        /* Stream from which to release a reference */
  328. } FsStreamReleaseParam;
  329.  
  330. typedef struct {
  331.     Boolean    inUse;        /* TRUE if stream still in use after release */
  332. } FsStreamReleaseReply;
  333.  
  334. typedef struct {
  335.     Boolean    inUse;        /* TRUE if stream still in use after release */
  336.     int        offset;        /* Offset of stream on source of migration. */
  337. } FsStreamReleaseReplyNew;
  338.  
  339. /*
  340.  *----------------------------------------------------------------------
  341.  *
  342.  * StreamMigCallback --
  343.  *
  344.  *    Call back to the source client of a migration and tell it to
  345.  *    release its stream.  This invokes Fsio_StreamMigrate on the
  346.  *    remote client
  347.  *
  348.  * Results:
  349.  *    A return status.
  350.  *
  351.  * Side effects:
  352.  *      None.
  353.  *    
  354.  *----------------------------------------------------------------------
  355.  */
  356. static ReturnStatus
  357. StreamMigCallback(migInfoPtr, sharedPtr, offsetPtr)
  358.     Fsio_MigInfo    *migInfoPtr;    /* Encapsulated information */
  359.     Boolean    *sharedPtr;    /* TRUE if stream still used on client */
  360.     int     *offsetPtr;    /* Offset of stream on client */
  361. {
  362.     register ReturnStatus    status;
  363.     Rpc_Storage         storage;
  364.     FsStreamReleaseParam    param;
  365.     FsStreamReleaseReply    reply;
  366.     FsStreamReleaseReplyNew    replyNew;
  367.  
  368.     param.streamID = migInfoPtr->streamID;
  369.     storage.requestParamPtr = (Address) ¶m;
  370.     storage.requestParamSize = sizeof(param);
  371.     storage.requestDataPtr = (Address)NIL;
  372.     storage.requestDataSize = 0;
  373.  
  374.     replyNew.inUse = FALSE;
  375.     storage.replyParamPtr = (Address)&replyNew;
  376.     storage.replyParamSize = sizeof(replyNew);
  377.     storage.replyDataPtr = (Address) NIL;
  378.     storage.replyDataSize = 0;
  379.  
  380.     status = Rpc_Call(migInfoPtr->srcClientID, RPC_FS_RELEASE_NEW, &storage);
  381.  
  382.     if (status == RPC_INVALID_RPC) {
  383.  
  384.     if (proc_MigDebugLevel > 2) {
  385.         printf("StreamMigCallback: client %d doesn't support new RPC.\n",
  386.            migInfoPtr->srcClientID);
  387.     }
  388.     reply.inUse = FALSE;
  389.     storage.replyParamPtr = (Address)&reply;
  390.     storage.replyParamSize = sizeof(reply);
  391.     storage.replyDataPtr = (Address) NIL;
  392.     storage.replyDataSize = 0;
  393.  
  394.     status = Rpc_Call(migInfoPtr->srcClientID, RPC_FS_RELEASE, &storage);
  395.  
  396.     *sharedPtr = reply.inUse;
  397.     *offsetPtr = -1;
  398.     } else {
  399.     *sharedPtr = replyNew.inUse;
  400.     *offsetPtr = replyNew.offset;
  401.     }
  402. #ifdef NOTDEF
  403.     if (status != SUCCESS && fsio_MigDebug) {
  404.     printf("StreamMigCallback: status %x from RPC.\n", status);
  405.     }
  406. #endif
  407.     return(status);
  408. }
  409.  
  410. /*
  411.  *----------------------------------------------------------------------
  412.  *
  413.  * Fsio_RpcStreamMigClose --
  414.  *
  415.  *    The service stub for FsStreamMigCallback.
  416.  *    This invokes the StreamMigrate routine that releases a reference
  417.  *    to a stream on this host.  Our reply message indicates if
  418.  *    the stream is still in use on this host.
  419.  *
  420.  * Results:
  421.  *    FS_STALE_HANDLE if handle that if client that is migrating the file
  422.  *    doesn't have the file opened on this machine.  Otherwise return
  423.  *    SUCCESS.
  424.  *
  425.  * Side effects:
  426.  *    None.
  427.  *
  428.  *----------------------------------------------------------------------
  429.  */
  430. /*ARGSUSED*/
  431. ReturnStatus
  432. Fsio_RpcStreamMigClose(srvToken, clientID, command, storagePtr)
  433.     ClientData srvToken;    /* Handle on server process passed to
  434.                  * Rpc_Reply */
  435.     int clientID;        /* Sprite ID of client host */
  436.     int command;        /* Command identifier */
  437.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  438.                  * buffers and also indicate the exact amount
  439.                  * of data in the request buffers.  The reply
  440.                  * fields are initialized to NIL for the
  441.                  * pointers and 0 for the lengths.  This can
  442.                  * be passed to Rpc_Reply */
  443. {
  444.     register FsStreamReleaseParam    *paramPtr;
  445.     register Fs_Stream            *streamPtr;
  446.     register ReturnStatus        status;
  447.     register FsStreamReleaseReply    *replyPtr;
  448.     register Rpc_ReplyMem        *replyMemPtr;
  449.  
  450.     paramPtr = (FsStreamReleaseParam *) storagePtr->requestParamPtr;
  451.  
  452.     streamPtr = Fsio_StreamClientVerify(¶mPtr->streamID,
  453.                 (Fs_HandleHeader *)NIL, rpc_SpriteID);
  454.     if (streamPtr == (Fs_Stream *) NIL) {
  455.     printf("Fsio_RpcStreamMigClose, unknown stream <%d>, client %d\n",
  456.         paramPtr->streamID.minor, clientID);
  457.     return( (paramPtr->streamID.minor < 0) ? GEN_INVALID_ARG
  458.                            : FS_STALE_HANDLE);
  459.     }
  460.     replyPtr = mnew(FsStreamReleaseReply);
  461.     storagePtr->replyParamPtr = (Address)replyPtr;
  462.     storagePtr->replyParamSize = sizeof(FsStreamReleaseReply);
  463.     storagePtr->replyDataPtr = (Address)NIL;
  464.     storagePtr->replyDataSize = 0;
  465.  
  466.     status = Fsio_StreamMigClose(streamPtr, &replyPtr->inUse);
  467.  
  468.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  469.     replyMemPtr->paramPtr = storagePtr->replyParamPtr;
  470.     replyMemPtr->dataPtr = (Address) NIL;
  471.     Rpc_Reply(srvToken, status, storagePtr, Rpc_FreeMem,
  472.         (ClientData)replyMemPtr);
  473.     return(SUCCESS);
  474. }
  475.  
  476.  
  477. /*
  478.  *----------------------------------------------------------------------
  479.  *
  480.  * Fsio_RpcStreamMigCloseNew --
  481.  *
  482.  *    The service stub for FsStreamMigCallback.
  483.  *    This invokes the StreamMigrate routine that releases a reference
  484.  *    to a stream on this host.  Our reply message indicates if
  485.  *    the stream is still in use on this host, and what its offset is.
  486.  *
  487.  * Results:
  488.  *    FS_STALE_HANDLE if handle that if client that is migrating the file
  489.  *    doesn't have the file opened on this machine.  Otherwise return
  490.  *    SUCCESS.  
  491.  *
  492.  * Side effects:
  493.  *    None.
  494.  *
  495.  *----------------------------------------------------------------------
  496.  */
  497. /*ARGSUSED*/
  498. ReturnStatus
  499. Fsio_RpcStreamMigCloseNew(srvToken, clientID, command, storagePtr)
  500.     ClientData srvToken;    /* Handle on server process passed to
  501.                  * Rpc_Reply */
  502.     int clientID;        /* Sprite ID of client host */
  503.     int command;        /* Command identifier */
  504.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  505.                  * buffers and also indicate the exact amount
  506.                  * of data in the request buffers.  The reply
  507.                  * fields are initialized to NIL for the
  508.                  * pointers and 0 for the lengths.  This can
  509.                  * be passed to Rpc_Reply */
  510. {
  511.     register FsStreamReleaseParam    *paramPtr;
  512.     register Fs_Stream            *streamPtr;
  513.     register ReturnStatus        status;
  514.     register FsStreamReleaseReplyNew    *replyPtr;
  515.     register Rpc_ReplyMem        *replyMemPtr;
  516.  
  517.     paramPtr = (FsStreamReleaseParam *) storagePtr->requestParamPtr;
  518.  
  519.     streamPtr = Fsio_StreamClientVerify(¶mPtr->streamID,
  520.                 (Fs_HandleHeader *)NIL, rpc_SpriteID);
  521.     if (streamPtr == (Fs_Stream *) NIL) {
  522.     printf("Fsio_RpcStreamMigClose, unknown stream <%d>, client %d\n",
  523.         paramPtr->streamID.minor, clientID);
  524.     return( (paramPtr->streamID.minor < 0) ? GEN_INVALID_ARG
  525.                            : FS_STALE_HANDLE);
  526.     }
  527.     replyPtr = mnew(FsStreamReleaseReplyNew);
  528.     storagePtr->replyParamPtr = (Address)replyPtr;
  529.     storagePtr->replyParamSize = sizeof(FsStreamReleaseReplyNew);
  530.     storagePtr->replyDataPtr = (Address)NIL;
  531.     storagePtr->replyDataSize = 0;
  532.  
  533.     status = Fsio_StreamMigCloseNew(streamPtr, &replyPtr->inUse,
  534.                     &replyPtr->offset);
  535.  
  536.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  537.     replyMemPtr->paramPtr = storagePtr->replyParamPtr;
  538.     replyMemPtr->dataPtr = (Address) NIL;
  539.     Rpc_Reply(srvToken, status, storagePtr, Rpc_FreeMem,
  540.         (ClientData)replyMemPtr);
  541.     return(SUCCESS);
  542. }
  543.  
  544. /*
  545.  * ----------------------------------------------------------------------------
  546.  *
  547.  * Fsio_StreamMigClose --
  548.  *
  549.  *    This is called to release a reference to a stream at the source
  550.  *    of a migration.  We are told to release the reference by the
  551.  *    I/O server during its Fsio_StreamMigClient call.  The timing of our
  552.  *    call ensures that a simultaneous Fs_Close on the stream will be
  553.  *    properly synchronized - the I/O server has to know how many
  554.  *    stream references we, the source of a migration, really have.
  555.  *
  556.  * Results:
  557.  *    SUCCESS unless the stream isn't even found.  This sets the FS_RMT_SHARED
  558.  *    flag in the *flagsPtr field if the stream is still in use here,
  559.  *    otherwise it clears this flag.
  560.  *
  561.  * Side effects:
  562.  *    This releases one reference to the stream.  If it is the last
  563.  *    reference then this propogates the close down to the I/O handle
  564.  *    by calling the stream-specific release procedure.
  565.  *
  566.  * ----------------------------------------------------------------------------
  567.  *
  568.  */
  569. /*ARGSUSED*/
  570. ReturnStatus
  571. Fsio_StreamMigClose(streamPtr, inUsePtr)
  572.     Fs_Stream *streamPtr;    /* Stream to release, should be locked */
  573.     Boolean *inUsePtr;        /* TRUE if still in use after release */
  574. {
  575.     /*
  576.      * Release the reference that has now migrated away.
  577.      */
  578.     Fsutil_HandleDecRefCount((Fs_HandleHeader *)streamPtr);
  579.     /*
  580.      * If this is the last reference then call down to the I/O handle
  581.      * so it can decrement use counts that come from the stream.
  582.      * (Remember there is still one reference from Fsio_RpcStreamMigClose)
  583.      */
  584.     if (streamPtr->hdr.refCount <= 1) {
  585.     (*fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].release)
  586.         (streamPtr->ioHandlePtr, streamPtr->flags);
  587.     if (Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID)) {
  588.         /*
  589.          * No references, no other clients, nuke it.
  590.          */
  591.         *inUsePtr = FALSE;
  592.         Fsio_StreamDestroy(streamPtr);
  593.         return(SUCCESS);
  594.     }
  595.     }
  596.     *inUsePtr = TRUE;
  597.     streamPtr->flags |= FS_RMT_SHARED;
  598.     Fsutil_HandleRelease(streamPtr, TRUE);
  599.     return(SUCCESS);
  600. }
  601.  
  602. /*
  603.  * ----------------------------------------------------------------------------
  604.  *
  605.  * Fsio_StreamMigCloseNew --
  606.  *
  607.  *    This is called to release a reference to a stream at the source
  608.  *    of a migration.  We are told to release the reference by the
  609.  *    I/O server during its Fsio_StreamMigClient call.  The timing of our
  610.  *    call ensures that a simultaneous Fs_Close on the stream will be
  611.  *    properly synchronized - the I/O server has to know how many
  612.  *    stream references we, the source of a migration, really have.  It also
  613.  *    keeps the offset consistent in the face of operations after
  614.  *    encapsulation.
  615.  *
  616.  * Results:
  617.  *    SUCCESS unless the stream isn't even found.  This sets *inUsePtr
  618.  *    if the stream is still in use here, otherwise it clears this flag.
  619.  *    This also sets *offsetPtr to the current offset of the stream.
  620.  *
  621.  * Side effects:
  622.  *    This releases one reference to the stream.  If it is the last
  623.  *    reference then this propogates the close down to the I/O handle
  624.  *    by calling the stream-specific release procedure.
  625.  *
  626.  * ----------------------------------------------------------------------------
  627.  *
  628.  */
  629. /*ARGSUSED*/
  630. ReturnStatus
  631. Fsio_StreamMigCloseNew(streamPtr, inUsePtr, offsetPtr)
  632.     Fs_Stream *streamPtr;    /* Stream to release, should be locked */
  633.     Boolean *inUsePtr;        /* TRUE if still in use after release */
  634.     int *offsetPtr;        /* Current stream offset */
  635. {
  636.     /*
  637.      * Set the offset we are passing back to the I/O server.
  638.      */
  639.     *offsetPtr = streamPtr->offset;
  640.     /*
  641.      * Release the reference that has now migrated away.
  642.      */
  643.     Fsutil_HandleDecRefCount((Fs_HandleHeader *)streamPtr);
  644.     /*
  645.      * If this is the last reference then call down to the I/O handle
  646.      * so it can decrement use counts that come from the stream.
  647.      * (Remember there is still one reference from Fsio_RpcStreamMigClose)
  648.      */
  649.     if (streamPtr->hdr.refCount <= 1) {
  650.     (*fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].release)
  651.         (streamPtr->ioHandlePtr, streamPtr->flags);
  652.     if (Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID)) {
  653.         /*
  654.          * No references, no other clients, nuke it.
  655.          */
  656.         *inUsePtr = FALSE;
  657.         Fsio_StreamDestroy(streamPtr);
  658.         return(SUCCESS);
  659.     }
  660.     }
  661.     *inUsePtr = TRUE;
  662.     streamPtr->flags |= FS_RMT_SHARED;
  663.     Fsutil_HandleRelease(streamPtr, TRUE);
  664.     return(SUCCESS);
  665. }
  666.  
  667. /*
  668.  *----------------------------------------------------------------------
  669.  *
  670.  * Fsio_StreamCreateID --
  671.  *
  672.  *    Generate a new streamID for a client.  This chooses a unique minor
  673.  *    number for the    fileID of the stream and returns the fileID.  This
  674.  *    is used on the file server to generate IDs for remote device streams.
  675.  *    This ID will be used to create matching streams on the device I/O server
  676.  *    and on the client's machine.
  677.  *
  678.  * Results:
  679.  *    A unique fileID for a stream to the given I/O server.
  680.  *
  681.  * Side effects:
  682.  *    Increment the global streamCount used to generate IDs.
  683.  *
  684.  *----------------------------------------------------------------------
  685.  */
  686. ENTRY void
  687. Fsio_StreamCreateID(serverID, streamIDPtr)
  688.     int            serverID;    /* I/O server for stream */
  689.     Fs_FileID        *streamIDPtr;    /* Return - FileID for the stream */
  690. {
  691.     register Boolean found;
  692.     Fs_Stream *newStreamPtr;
  693.     Fs_FileID fileID;
  694.  
  695.     LOCK_MONITOR;
  696.  
  697.     /*
  698.      * The streamID is uniquified by using our own host ID for the major
  699.      * field (for network uniqueness), and then choosing minor
  700.      * numbers until we don't have a local conflict.
  701.      */
  702.     fileID.type = FSIO_STREAM;
  703.     fileID.serverID = serverID;
  704.     fileID.major = rpc_SpriteID;
  705.  
  706.     do {
  707.     fileID.minor = ++streamCount;
  708.     found = Fsutil_HandleInstall(&fileID, sizeof(Fs_Stream), (char *)NIL,
  709.                 FALSE, (Fs_HandleHeader **)&newStreamPtr);
  710.     if (found) {
  711.         /*
  712.          * Don't want to conflict with existing streams.
  713.          */
  714.         Fsutil_HandleRelease(newStreamPtr, TRUE);
  715.     }
  716.     } while (found);
  717.     *streamIDPtr = newStreamPtr->hdr.fileID;
  718.     Fsutil_HandleRelease(newStreamPtr, TRUE);
  719.     Fsutil_HandleRemove(newStreamPtr);
  720.     UNLOCK_MONITOR;
  721. }
  722.  
  723. /*
  724.  *----------------------------------------------------------------------
  725.  *
  726.  * Fsio_StreamCopy --
  727.  *
  728.  *    Duplicate a stream.  This ups the reference count on the stream
  729.  *    so that it won't go away until its last user closes it.
  730.  *
  731.  * Results:
  732.  *    None.
  733.  *
  734.  * Side effects:
  735.  *    The reference count on the stream is incremented.
  736.  *
  737.  *----------------------------------------------------------------------
  738.  */
  739. ENTRY void
  740. Fsio_StreamCopy(oldStreamPtr, newStreamPtrPtr)
  741.     Fs_Stream *oldStreamPtr;
  742.     Fs_Stream **newStreamPtrPtr;
  743. {
  744.     *newStreamPtrPtr = Fsutil_HandleDupType(Fs_Stream, oldStreamPtr);
  745.     Fsutil_HandleUnlock(oldStreamPtr);
  746. }
  747.  
  748. /*
  749.  *----------------------------------------------------------------------
  750.  *
  751.  * Fsio_StreamClientVerify --
  752.  *
  753.  *    Verify that the remote client is known for the stream, and return
  754.  *    a locked pointer to the stream's handle.
  755.  *
  756.  * Results:
  757.  *    A pointer to the handle for the stream, or NIL if
  758.  *    the client is bad.
  759.  *
  760.  * Side effects:
  761.  *    The handle is returned locked and with its refCount incremented.
  762.  *    It should be released with Fsutil_HandleRelease(..., TRUE)
  763.  *
  764.  *----------------------------------------------------------------------
  765.  */
  766.  
  767. Fs_Stream *
  768. Fsio_StreamClientVerify(streamIDPtr, ioHandlePtr, clientID)
  769.     Fs_FileID    *streamIDPtr;        /* Client's stream ID */
  770.     Fs_HandleHeader *ioHandlePtr;    /* I/O handle the client thinks
  771.                      * is attached to the stream */
  772.     int        clientID;        /* Host ID of the client */
  773. {
  774.     register FsioStreamClient *clientPtr;
  775.     register Fs_Stream *streamPtr;
  776.     Boolean found = FALSE;
  777.  
  778.     streamPtr = Fsutil_HandleFetchType(Fs_Stream, streamIDPtr);
  779.     if (streamPtr != (Fs_Stream *)NIL) {
  780.     LIST_FORALL(&streamPtr->clientList, (List_Links *) clientPtr) {
  781.         if (clientPtr->clientID == clientID) {
  782.         found = TRUE;
  783.         break;
  784.         }
  785.     }
  786.     if (!found) {
  787.         printf("Fsio_StreamClientVerify: no client %d for stream <%d> \"%s\"\n",
  788.         clientID, streamPtr->hdr.fileID.minor,
  789.         Fsutil_HandleName((Fs_HandleHeader *)streamPtr));
  790.         Fsutil_HandleRelease(streamPtr, TRUE);
  791.         streamPtr = (Fs_Stream *)NIL;
  792.  
  793.     } else if (ioHandlePtr != (Fs_HandleHeader *)NIL &&
  794.            streamPtr->ioHandlePtr != ioHandlePtr) {
  795.         /*
  796.          * The client's stream doesn't reference the same handle as we do.
  797.          * Note that ioHandlePtr is NIL when we are called from
  798.          * Fsio_RpcStreamMigClose, so we can't make this check in that case.
  799.          */
  800.         printf("Fsio_StreamClientVerify ioHandle mismatch client ID %d:\n",
  801.             clientID);
  802.         if (streamPtr->ioHandlePtr == (Fs_HandleHeader *)NIL) {
  803.         printf("\tStream <%d> \"%s\" my I/O handle NIL\n",
  804.             Fsutil_HandleName(streamPtr), streamIDPtr->minor);
  805.         } else {
  806.         printf("\tStream <%d> my handle %s \"%s\" <%d,%d>\n",
  807.             streamIDPtr->minor,
  808.             Fsutil_FileTypeToString(streamPtr->ioHandlePtr->fileID.type),
  809.             Fsutil_HandleName(streamPtr->ioHandlePtr),
  810.             streamPtr->ioHandlePtr->fileID.major,
  811.             streamPtr->ioHandlePtr->fileID.minor);
  812.         }
  813.         printf("\tClient %d handle %s \"%s\" <%d,%d>\n",
  814.             clientID, Fsutil_HandleName(ioHandlePtr),
  815.             Fsutil_FileTypeToString(ioHandlePtr->fileID.type),
  816.             ioHandlePtr->fileID.major, ioHandlePtr->fileID.minor);
  817.        Fsutil_HandleRelease(streamPtr, TRUE);
  818.        streamPtr = (Fs_Stream *)NIL;
  819.     }
  820.     } else {
  821.     printf("No stream <%d> for client %d\n", streamIDPtr->minor, clientID);
  822.     }
  823.     return(streamPtr);
  824. }
  825.  
  826.  
  827. /*
  828.  *----------------------------------------------------------------------
  829.  *
  830.  * Fsio_StreamClientKill --
  831.  *
  832.  *    Called when a client is assumed down.  This cleans up the
  833.  *    client list for the stream or removes the stream.
  834.  *
  835.  * Results:
  836.  *    None.
  837.  *
  838.  * Side effects:
  839.  *    Removes the client list entry for the client.
  840.  *    It removes or unlocks the handle.
  841.  *
  842.  *----------------------------------------------------------------------
  843.  */
  844. void
  845. Fsio_StreamClientKill(hdrPtr, clientID)
  846.     Fs_HandleHeader    *hdrPtr;    /* Stream to clean up */
  847.     int            clientID;    /* Host assumed down */
  848. {
  849.     Fs_Stream        *streamPtr = (Fs_Stream *) hdrPtr;
  850.  
  851.     if (!Fsio_StreamClientClose(&streamPtr->clientList, clientID)) {
  852.     /*
  853.      * There were other clients.
  854.      */
  855.     Fsutil_HandleUnlock(streamPtr);
  856.     } else {
  857.     Fsutil_HandleRemove(streamPtr);
  858.     }
  859. }
  860.  
  861.  
  862. /*
  863.  *----------------------------------------------------------------------
  864.  *
  865.  * Fsio_StreamDestroy --
  866.  *
  867.  *    Discard a stream.  This call removes the stream from the handle
  868.  *    table and frees associated storage.  The I/O handle pointer part
  869.  *    should have already been cleaned up by its handler.
  870.  *
  871.  *    If the stream still has associated clients, release the reference
  872.  *    to the stream but don't get rid of the stream, since it is a shadow
  873.  *    stream.
  874.  *
  875.  * Results:
  876.  *    None.
  877.  *
  878.  * Side effects:
  879.  *    Remove the stream handle from the handle table.
  880.  *
  881.  *----------------------------------------------------------------------
  882.  */
  883.  
  884. Boolean fsio_StreamDisposeDebug = TRUE;
  885.  
  886. ENTRY void
  887. Fsio_StreamDestroy(streamPtr)
  888.     register Fs_Stream *streamPtr;
  889. {
  890.     Boolean noClients = TRUE;
  891.     
  892.     if (!List_IsEmpty(&streamPtr->clientList)) {
  893.     noClients = FALSE;
  894.     if (fsio_StreamDisposeDebug) {
  895.         register FsioStreamClient *clientPtr;
  896.  
  897.         LIST_FORALL(&streamPtr->clientList, (List_Links *) clientPtr) {
  898.  
  899.         printf("Fsio_StreamDestroy, client %d still in list for stream <%d,%d>, refCount %d\n",
  900.               clientPtr->clientID, streamPtr->hdr.fileID.major,
  901.               streamPtr->hdr.fileID.minor, streamPtr->hdr.refCount);
  902.         if (streamPtr->ioHandlePtr != (Fs_HandleHeader *)NIL) {
  903.             printf("\tI/O handle: %s <%d,%d>, refCount %d\n",
  904.                    Fsutil_FileTypeToString(streamPtr->ioHandlePtr->fileID.type),
  905.                    streamPtr->ioHandlePtr->fileID.major,
  906.                    streamPtr->ioHandlePtr->fileID.minor,
  907.                    streamPtr->ioHandlePtr->refCount);
  908.         }
  909.         }
  910.     }
  911.     } 
  912.  
  913.     Fsutil_HandleRelease(streamPtr, TRUE);
  914.     if (noClients) {
  915.     if (streamPtr->nameInfoPtr != (Fs_NameInfo *)NIL) {
  916.         free((Address)streamPtr->nameInfoPtr);
  917.     }
  918.     Fsutil_HandleRemove(streamPtr);
  919.     fs_Stats.object.streams--;
  920.     }
  921. }
  922.  
  923. /*
  924.  *----------------------------------------------------------------------
  925.  *
  926.  * Fsio_StreamScavenge --
  927.  *
  928.  *    Scavenge a stream.  Servers may have no references to a stream handle,
  929.  *    but still have some things on its client list.  Clients have
  930.  *    references, but no client list.  A stream with neither references
  931.  *    or a client list is scavengable.
  932.  *
  933.  * Results:
  934.  *    None.
  935.  *
  936.  * Side effects:
  937.  *    Removes the stream handle if it has no references and no clients.
  938.  *
  939.  *----------------------------------------------------------------------
  940.  */
  941. #ifdef notdef
  942. Boolean
  943. Fsio_StreamScavenge(hdrPtr)
  944.     Fs_HandleHeader *hdrPtr;
  945. {
  946.     register Fs_Stream *streamPtr = (Fs_Stream *)hdrPtr;
  947.  
  948.     if (streamPtr->hdr.refCount == 0 &&
  949.     List_IsEmpty(&streamPtr->clientList)) {
  950.     printf( "Fsio_StreamScavenge, removing stream <%d,%d>\n",
  951.         streamPtr->hdr.fileID.serverID,
  952.         streamPtr->hdr.fileID.minor);
  953.     Fsutil_HandleRemove((Fs_HandleHeader *)streamPtr);
  954.     fs_Stats.object.streams--;
  955.     return(TRUE);
  956.     } else {
  957.     Fsutil_HandleUnlock((Fs_HandleHeader *)streamPtr);
  958.     return(FALSE);
  959.     }
  960. }
  961. #endif notdef
  962.  
  963.  
  964. typedef struct StreamReopenParams {
  965.     Fs_FileID    streamID;
  966.     Fs_FileID    ioFileID;
  967.     int        useFlags;
  968.     int        offset;
  969. } StreamReopenParams;
  970.  
  971. /*
  972.  *----------------------------------------------------------------------
  973.  *
  974.  * Fsio_StreamReopen --
  975.  *
  976.  *    This is called initially on the client side from FsHandleReopen.
  977.  *    That instance then does an RPC to the server, which again invokes
  978.  *    this routine.  On the client side we don't do much except pass
  979.  *    over the streamID and the ioHandle fileID so the server can
  980.  *    re-create state.  On the server we have to re-setup the stream,
  981.  *    which is sort of a pain because it must reference the correct
  982.  *    I/O handle.
  983.  *
  984.  * Results:
  985.  *    SUCCESS if the stream was reopened.
  986.  *
  987.  * Side effects:
  988.  *    On the client, do an RPC to the server.
  989.  *    On the server, re-create the stream.
  990.  *
  991.  *----------------------------------------------------------------------
  992.  */
  993. /*ARGSUSED*/
  994. ENTRY ReturnStatus
  995. Fsio_StreamReopen(hdrPtr, clientID, inData, outSizePtr, outDataPtr)
  996.     Fs_HandleHeader    *hdrPtr;    /* Stream's handle header */
  997.     int            clientID;
  998.     ClientData        inData;        /* Non-NIL on the server */
  999.     int            *outSizePtr;    /* Non-NIL on the server */
  1000.     ClientData        *outDataPtr;    /* Non-NIL on the server */
  1001. {
  1002.     register Fs_Stream    *streamPtr = (Fs_Stream *)hdrPtr;
  1003.     ReturnStatus status;
  1004.  
  1005.     if (inData == (ClientData)NIL) {
  1006.     /*
  1007.      * Called on the client side.  We contact the server to invoke
  1008.      * this procedure there with some input parameters.
  1009.      */
  1010.     StreamReopenParams reopenParams;
  1011.     int outSize = 0;
  1012.  
  1013.     reopenParams.streamID = hdrPtr->fileID;
  1014.     reopenParams.ioFileID = streamPtr->ioHandlePtr->fileID;
  1015.     reopenParams.useFlags = streamPtr->flags;
  1016.     reopenParams.offset   = streamPtr->offset;
  1017.     /*
  1018.      * This is a mousetrap to catch the "poison packets" reported in
  1019.      * log message 30402.  It can be removed once that bug is fixed.
  1020.      * JHH 12/10/90
  1021.      */
  1022.     if (reopenParams.ioFileID.type == -1) {
  1023.         panic("About to reopen stream with ioFileID.type set to -1\n");
  1024.     }
  1025.     status = FsrmtReopen(hdrPtr, sizeof(reopenParams),
  1026.             (Address)&reopenParams, &outSize, (Address)NIL);
  1027.     /*
  1028.      * This here is the server side fix for the "poison packet" bug.
  1029.      * Ignore the request if the type is -1.  Remove this when
  1030.      * the bug is fixed.
  1031.      * JHH 12/10/90
  1032.      */
  1033.     } else if (((StreamReopenParams *) inData)->ioFileID.type < 0 ||
  1034.         ((StreamReopenParams *) inData)->ioFileID.type >=
  1035.         FSIO_NUM_STREAM_TYPES) {
  1036.     printf("Fsio_StreamReopen: fileID type = 0x%x from client %d\n",
  1037.         ((StreamReopenParams *) inData)->ioFileID.type, clientID);
  1038.     status = FAILURE;
  1039.     } else {
  1040.     /*
  1041.      * Called on the server side.  We need to first make sure there
  1042.      * is a corresponding I/O handle for the stream, and then we
  1043.      * can set up the stream.
  1044.      */
  1045.     StreamReopenParams    *reopenParamsPtr;
  1046.     register Fs_FileID    *fileIDPtr;
  1047.     Fs_HandleHeader        *ioHandlePtr;
  1048.     /* 
  1049.      * Note about shared stream recovery.  We loose the offset of
  1050.      * a shared stream during a crash.  We just print a message and
  1051.      * try to go forward.  Often the shared stream is for a process's
  1052.      * current working directory, so the offset doesn't matter.
  1053.      */
  1054.     Boolean            patchOffset = FALSE;
  1055.  
  1056.     reopenParamsPtr = (StreamReopenParams *)inData;
  1057.     fileIDPtr = &reopenParamsPtr->ioFileID;
  1058.     ioHandlePtr = (*fsio_StreamOpTable[fileIDPtr->type].clientVerify)
  1059.             (fileIDPtr, clientID, (int *)NIL);
  1060.     if (ioHandlePtr != (Fs_HandleHeader *)NIL) {
  1061.         status = SUCCESS;
  1062.         streamPtr = Fsutil_HandleFetchType(Fs_Stream,
  1063.             &reopenParamsPtr->streamID);
  1064.         if (streamPtr != (Fs_Stream *)NIL) {
  1065.         /*
  1066.          * Verify that we have the stream hooked to the same
  1067.          * I/O handle as the client.  It is possible that we
  1068.          * have reused the client's stream ID with a different
  1069.          * I/O handle, in which case the client loses this stream.
  1070.          */
  1071.         if (streamPtr->ioHandlePtr != ioHandlePtr) {
  1072.             printf("Fsio_StreamReopen, I/O handle mismatch, client %d its I/O <%d,%d> my I/O <%d,%d>\n",
  1073.             clientID,
  1074.             ioHandlePtr->fileID.major,
  1075.             ioHandlePtr->fileID.minor,
  1076.             streamPtr->ioHandlePtr->fileID.major,
  1077.             streamPtr->ioHandlePtr->fileID.minor);
  1078.             status = FAILURE;
  1079.         } else if ((reopenParamsPtr->useFlags & FS_RMT_SHARED) &&
  1080.                (streamPtr->flags & FS_RMT_SHARED) == 0) {
  1081.             /*
  1082.              * The client thinks the stream is shared by processes
  1083.              * on a different client, but we lost the shadow stream.
  1084.              * (If we do think the stream is shared things are ok.)
  1085.              */
  1086.             printf("Fsio_StreamReopen, not a shadow stream, client %d stream <%d> client I/O <%d,%d>\n",
  1087.                 clientID, streamPtr->hdr.fileID.minor,
  1088.                 ioHandlePtr->fileID.major,
  1089.                 ioHandlePtr->fileID.minor);
  1090.             status = FAILURE;
  1091.         }
  1092.         Fsutil_HandleRelease(streamPtr, TRUE);
  1093.         } else if (reopenParamsPtr->useFlags & FS_RMT_SHARED) {
  1094.         /*
  1095.          * The client thinks the stream is shared by processes
  1096.          * on a different client, but we don't have a shadow stream.
  1097.          */
  1098.         printf("Fsio_StreamReopen, lost shared stream offset? using offset (%d), client %d, I/O <%d,%d> \"%s\"\n",
  1099.             reopenParamsPtr->offset, clientID,
  1100.             ioHandlePtr->fileID.major,
  1101.             ioHandlePtr->fileID.minor,
  1102.             Fsutil_HandleName(ioHandlePtr));
  1103.         patchOffset = TRUE;
  1104.         }
  1105.         if (status == SUCCESS) {
  1106.         streamPtr = Fsio_StreamAddClient(&reopenParamsPtr->streamID,
  1107.             clientID, ioHandlePtr, reopenParamsPtr->useFlags,
  1108.             ioHandlePtr->name, (Boolean *)NIL, (Boolean *)NIL);
  1109.         /*
  1110.          * There isn't proper recovery of the offset if the stream
  1111.          * was shared when we crashed, but here we fake it.
  1112.          */
  1113.         if (patchOffset) {
  1114.             streamPtr->offset = reopenParamsPtr->offset;
  1115.         }
  1116.         Fsutil_HandleRelease(streamPtr, TRUE);
  1117.         }
  1118.         Fsutil_HandleRelease(ioHandlePtr, TRUE);
  1119.     } else {
  1120.         printf("Fsio_StreamReopen, %s I/O handle <%d,%d> not found\n",
  1121.         Fsutil_FileTypeToString(fileIDPtr->type),
  1122.         fileIDPtr->major, fileIDPtr->minor);
  1123.         status = FAILURE;
  1124.     }
  1125.     }
  1126.     return(status);
  1127. }
  1128.